﻿using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using TCPActivePull.Config;

namespace TCPActivePull.Service;

public class IndustrialClientService : BackgroundService
{
    private readonly TcpClientConfig _clientConfig;
    private readonly ILogger<IndustrialClientService> _logger;
    private TcpClient? _tcpClient;
    private NetworkStream? _stream;
    private readonly JsonSerializerOptions _jsonOptions;
    private Timer? _heartbeatTimer;

    // 【新增】缓冲区用于累积不完整消息
    private readonly StringBuilder _dataBuffer = new StringBuilder();
    // 【新增】消息分隔符（必须与服务端保持一致）
    private const string MessageSeparator = "\n";

    // 配置常量
    private const int ReadTimeoutMs = 5000;
    private const int HeartbeatIntervalMs = 3000;

    // 日期时间转换器（与服务端完全一致）
    public class DateTimeConverterWithFormat : JsonConverter<DateTime>
    {
        private readonly string _format;

        public DateTimeConverterWithFormat(string format = "yyyy-MM-dd HH:mm:ss.fff")
        {
            _format = format;
        }

        public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (DateTime.TryParseExact(
                reader.GetString(),
                _format,
                System.Globalization.CultureInfo.InvariantCulture,
                System.Globalization.DateTimeStyles.None,
                out var dateTime))
            {
                return dateTime;
            }

            throw new FormatException($"无法解析日期：{reader.GetString()}，需符合格式{_format}");
        }

        public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString(_format));
        }
    }

    // 工业数据模型（确保与服务端完全一致）
    public class IndustrialData
    {
        public string DeviceId { get; set; } = string.Empty;
        public string DeviceIp { get; set; } = string.Empty;
        public string RegisterAddress { get; set; } = string.Empty; // 必须为string类型
        public string DataName { get; set; } = string.Empty;
        public double RawValue { get; set; }
        public double ActualValue { get; set; }
        public string Unit { get; set; } = string.Empty;
        public DateTime Timestamp { get; set; }
    }

    public IndustrialClientService(
        IOptions<TcpClientConfig> clientConfig,
        ILogger<IndustrialClientService> logger)
    {
        _clientConfig = clientConfig.Value ?? throw new ArgumentNullException(nameof(clientConfig));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));

        _jsonOptions = new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true,
            Converters = { new DateTimeConverterWithFormat() }
        };

        ValidateClientConfig();
    }

    private void ValidateClientConfig()
    {
        if (string.IsNullOrWhiteSpace(_clientConfig.ServerIp))
        {
            throw new InvalidOperationException("客户端配置：服务端IP不能为空");
        }

        if (_clientConfig.ServerPort < 1 || _clientConfig.ServerPort > 65535)
        {
            throw new InvalidOperationException($"客户端配置：服务端端口{_clientConfig.ServerPort}无效（需在1-65535范围内）");
        }

        if (_clientConfig.BufferSize < 1024)
        {
            _logger.LogWarning("客户端缓冲区过小（{BufferSize}字节），已自动调整为1024字节", _clientConfig.BufferSize);
            _clientConfig.BufferSize = 1024;
        }
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            "工业客户端启动，开始连接服务器（IP：{ServerIp}，端口：{ServerPort}）...",
            _clientConfig.ServerIp,
            _clientConfig.ServerPort
        );

        while (!stoppingToken.IsCancellationRequested)
        {
            if (_tcpClient == null || !_tcpClient.Connected)
            {
                _heartbeatTimer?.Dispose();
                await TryConnectToServerAsync(stoppingToken);
                await Task.Delay(_clientConfig.ReconnectIntervalMs, stoppingToken);
                continue;
            }

            if (_heartbeatTimer == null)
            {
                _heartbeatTimer = new Timer(
                    async _ => await SendHeartbeatAsync(stoppingToken),
                    null,
                    TimeSpan.Zero,
                    TimeSpan.FromMilliseconds(HeartbeatIntervalMs)
                );
            }

            await ReceiveAndProcessDataWithTimeoutAsync(stoppingToken);
        }
    }

    private async Task TryConnectToServerAsync(CancellationToken stoppingToken)
    {
        try
        {
            _tcpClient?.Dispose();
            _tcpClient = new TcpClient { NoDelay = true }; // 【新增】禁用Nagle算法，减少拆包
            using var connectCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
            connectCts.CancelAfter(5000);

            await _tcpClient.ConnectAsync(
                _clientConfig.ServerIp,
                _clientConfig.ServerPort,
                connectCts.Token
            );

            _stream = _tcpClient.GetStream();
            _dataBuffer.Clear(); // 【新增】连接成功后清空缓冲区
            _logger.LogInformation(
                "连接服务器成功（IP：{ServerIp}，端口：{ServerPort}）",
                _clientConfig.ServerIp,
                _clientConfig.ServerPort
            );
        }
        catch (OperationCanceledException)
        {
            _logger.LogWarning("连接服务器超时（5秒），{ReconnectMs}ms后重试", _clientConfig.ReconnectIntervalMs);
            Console.WriteLine($"连接超时，{_clientConfig.ReconnectIntervalMs}ms后重试...");
            CleanupConnections();
        }
        catch (SocketException ex)
        {
            _logger.LogError(ex, "连接服务器失败（IP：{ServerIp}，端口：{ServerPort}）：{Message}",
                _clientConfig.ServerIp, _clientConfig.ServerPort, ex.Message);
            Console.WriteLine($"连接服务器失败，{_clientConfig.ReconnectIntervalMs}ms后重试：{ex.Message}");
            CleanupConnections();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "连接服务器异常：{Message}", ex.Message);
            Console.WriteLine($"连接服务器异常，{_clientConfig.ReconnectIntervalMs}ms后重试：{ex.Message}");
            CleanupConnections();
        }
    }

    private async Task SendHeartbeatAsync(CancellationToken stoppingToken)
    {
        if (_stream == null || !_tcpClient!.Connected) return;

        try
        {
            // 【修改】心跳包添加分隔符，与服务端保持一致
            byte[] heartbeatData = Encoding.UTF8.GetBytes("HEARTBEAT" + MessageSeparator);
            await _stream.WriteAsync(heartbeatData, 0, heartbeatData.Length, stoppingToken);
            _logger.LogDebug("发送心跳包成功");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发送心跳包失败，触发重连");
            Console.WriteLine($"发送心跳消息失败，触发重连：{ex.Message}");
            CleanupConnections();
        }
    }

    private async Task ReceiveAndProcessDataWithTimeoutAsync(CancellationToken stoppingToken)
    {
        if (_stream == null || !_tcpClient!.Connected) return;

        try
        {
            byte[] buffer = new byte[_clientConfig.BufferSize];
            int bytesRead;

            using var readCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
            readCts.CancelAfter(ReadTimeoutMs);

            try
            {
                bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length, readCts.Token);
            }
            catch (OperationCanceledException)
            {
                _logger.LogDebug("读取数据超时（{ReadTimeout}ms），等待下次读取", ReadTimeoutMs);
                return;
            }

            if (bytesRead == 0)
            {
                _logger.LogWarning("服务器主动断开连接，触发重连");
                Console.WriteLine("服务器主动断开连接，触发重连");
                CleanupConnections();
                return;
            }

            // 【修改】将读取的数据追加到缓冲区，而不是直接处理
            string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead);
            _logger.LogDebug($"收到原始数据片段（{bytesRead}字节）：{receivedData}");
            _dataBuffer.Append(receivedData);

            // 【新增】处理缓冲区中的所有完整消息
            ProcessCompleteMessages();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "接收数据异常，触发重连");
            Console.WriteLine($"接收数据异常，触发重连：{ex.Message}");
            CleanupConnections();
        }
    }

    /// <summary>
    /// 【新增】处理缓冲区中所有完整的消息（按分隔符拆分）
    /// </summary>
    private void ProcessCompleteMessages()
    {
        string bufferContent = _dataBuffer.ToString();
        int separatorIndex;

        // 循环提取所有完整消息
        while ((separatorIndex = bufferContent.IndexOf(MessageSeparator)) != -1)
        {
            // 提取完整消息（从开头到分隔符前）
            string completeMessage = bufferContent.Substring(0, separatorIndex).Trim();
            // 更新缓冲区内容（保留分隔符后的剩余部分）
            bufferContent = bufferContent.Substring(separatorIndex + MessageSeparator.Length);

            // 处理非空消息
            if (!string.IsNullOrEmpty(completeMessage))
            {
                ProcessSingleCompleteMessage(completeMessage);
            }
        }

        // 更新缓冲区，保留未处理的部分
        _dataBuffer.Clear();
        _dataBuffer.Append(bufferContent);

        if (!string.IsNullOrEmpty(bufferContent))
        {
            _logger.LogDebug($"缓冲区保留未完整消息（等待后续数据）：{bufferContent}");
        }
    }

    /// <summary>
    /// 【新增】处理单个完整消息
    /// </summary>
    private void ProcessSingleCompleteMessage(string completeMessage)
    {
        // 忽略心跳响应
        if (completeMessage.Equals("HEARTBEAT_ACK", StringComparison.OrdinalIgnoreCase))
        {
            _logger.LogDebug("收到服务器心跳确认");
            return;
        }

        try
        {
            _logger.LogDebug($"开始解析完整消息：{completeMessage}");
            var industrialDatas = JsonSerializer.Deserialize<List<IndustrialData>>(completeMessage, _jsonOptions);

            if (industrialDatas == null || !industrialDatas.Any())
            {
                _logger.LogWarning("解析到空数据列表：{Json}", completeMessage);
                return;
            }

            ProcessIndustrialData(industrialDatas);
        }
        catch (JsonException ex)
        {
            _logger.LogError(ex, $"JSON解析失败！错误路径：{ex.Path} | 错误位置：行{ex.LineNumber}，列{ex.BytePositionInLine} | 原始消息：{completeMessage}");
            Console.WriteLine($"解析数据失败：{completeMessage}，错误：{ex.Message}（路径：{ex.Path}）");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"处理数据失败 | 原始消息：{completeMessage}");
            Console.WriteLine($"处理数据失败：{completeMessage}，错误：{ex.Message}");
        }
    }

    private void ProcessIndustrialData(List<IndustrialData> datas)
    {
        foreach (var data in datas)
        {
            _logger.LogInformation(
                "【客户端处理】{DataName}：{ActualValue}{Unit} " +
                "(设备ID：{DeviceId}，设备IP：{DeviceIp}，" +
                "寄存器：{RegisterAddress}，采集时间：{Timestamp:HH:mm:ss.fff})",
                data.DataName,
                data.ActualValue,
                data.Unit,
                data.DeviceId,
                data.DeviceIp,
                data.RegisterAddress,
                data.Timestamp
            );

            // TODO：数据持久化逻辑
        }
    }

    private void CleanupConnections()
    {
        try
        {
            _stream?.Dispose();
            if (_tcpClient?.Connected ?? false)
            {
                _tcpClient.Close();
            }
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "清理连接资源异常");
        }
        finally
        {
            _tcpClient = null;
            _stream = null;
        }
    }

    public override async Task StopAsync(CancellationToken cancellationToken)
    {
        _heartbeatTimer?.Dispose();
        CleanupConnections();
        await base.StopAsync(cancellationToken);
        _logger.LogInformation("工业客户端已停止");
    }
}
